package cn.xtcode.service.impl;

import cn.xtcode.common.constants.Constants;
import cn.xtcode.dao.IOrderDao;
import cn.xtcode.domain.dto.ProductDTO;
import cn.xtcode.domain.po.PayOrder;
import cn.xtcode.domain.req.ShopCartReq;
import cn.xtcode.domain.res.PayOrderRes;
import cn.xtcode.service.IOrderService;
import cn.xtcode.service.rpc.ProductRPC;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.google.common.eventbus.EventBus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author: xt-code
 * @date: 2025/8/6 11:02
 * @description:
 */
@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {
    @Resource
    private IOrderDao orderDao;

    @Resource
    private ProductRPC productRPC;

    @Resource
    private AlipayClient alipayClient;

    @Value("${alipay.notify_url}")
    private String notifyUrl;

    @Value("${alipay.return_url}")
    private String returnUrl;

    @Resource
    private EventBus eventBus;
    @Override
    public PayOrderRes createOrder(ShopCartReq shopCartReq) throws Exception {
        //1.查询当前用户是否存在未支付的订单
        PayOrder payOrderReq = new PayOrder();
        payOrderReq.setUserId(shopCartReq.getUserId());
        payOrderReq.setProductId(shopCartReq.getProductId());

        PayOrder unPayOrder = orderDao.queryUnpayOrder(payOrderReq);

        //用户对于该商品存在未支付订单，直接使用那一个订单即可。
        if (null != unPayOrder && Constants.OrderStatusEnum.PAY_WAIT.getCode().equals(unPayOrder.getStatus())) {
            log.info("创建订单-存在,已存在未支付订单。userId:{} productId:{} orderId:{}", shopCartReq.getUserId(), shopCartReq.getProductId(), unPayOrder.getOrderId());
            return PayOrderRes.builder()
                    .orderId(unPayOrder.getOrderId())
                    .payUrl(unPayOrder.getPayUrl())
                    .build();
        } else if (null != unPayOrder && Constants.OrderStatusEnum.CREATE.getCode().equals(unPayOrder.getStatus())) {
            //订单已经创建了，但是没有相关支付单。那么就需要支付单
            log.info("创建订单-存在，存在未创建支付单订单，创建支付单开始 userId:{} productId:{} orderId:{}", shopCartReq.getUserId(), shopCartReq.getProductId(), unPayOrder.getOrderId());
            PayOrder payOrder = doPrepayorder(unPayOrder.getProductId(), unPayOrder.getProductName(), unPayOrder.getOrderId(), unPayOrder.getTotalAmount());
            return PayOrderRes.builder()
                    .orderId(payOrder.getOrderId())
                    .payUrl(payOrder.getPayUrl())
                    .build();
        }

        //2.查询商品，创建订单 && 创建订单
        ProductDTO productDTO = productRPC.queryProductByProductId(shopCartReq.getProductId());
        if (null == productDTO) {
            log.error("获取商品id:{} 失败", shopCartReq.getProductId());
            throw new Exception("获取商品失败");
        }
        String orderId = RandomStringUtils.randomNumeric(16);


        orderDao.insert(
                PayOrder.builder()
                        .userId(shopCartReq.getUserId())
                        .productId(shopCartReq.getProductId())
                        .productName(productDTO.getProductName())
                        .orderId(orderId)
                        .totalAmount(productDTO.getPrice())
                        .orderTime(LocalDateTime.now())
                        .status(Constants.OrderStatusEnum.CREATE.getCode())
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .build()
        );

        //3.创建支付单
        PayOrder payOrder = doPrepayorder(productDTO.getProductId(), productDTO.getProductName(), orderId, productDTO.getPrice());


        return PayOrderRes.builder()
                .orderId(orderId)
                .payUrl(payOrder.getPayUrl())
                .build();
    }

    @Override
    public void changeOrderPaySuccess(String orderId) {
        PayOrder payOrder = new PayOrder();
        payOrder.setOrderId(orderId);
        payOrder.setStatus(Constants.OrderStatusEnum.PAY_SUCCESS.getCode());
        orderDao.changeOrderPaySuccess(payOrder);


        //MQ消息一般都使用JSON字符串发送
        eventBus.post(JSON.toJSONString(payOrder));
    }

    @Override
    public List<String> queryNoPayNotifyOrder() {
        return orderDao.queryNoPayNotifyOrder();
    }

    @Override
    public List<String> queryTimeoutCloseOrderList() {
        return orderDao.queryTimeoutCloseOrderList();
    }

    @Override
    public boolean changeOrderClose(String orderId) {
        return orderDao.changeOrderClose(orderId);
    }

    /**
     * 创建支付单使用的方法，由于它是
     *
     * @param productId
     * @param orderId
     * @param totalAmount
     * @return
     */
    private PayOrder doPrepayorder(String productId, String productName, String orderId, BigDecimal totalAmount) throws AlipayApiException {

        //1.根据aliAPI创建对象
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //支付成功后，回调的url
        request.setNotifyUrl(notifyUrl);
        //支付成功后，跳转的界面
        request.setReturnUrl(returnUrl);

        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderId);
        bizContent.put("total_amount", totalAmount.toString());
        bizContent.put("subject", productName);
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

        request.setBizContent(bizContent.toString());

        //2.创建支付单，返回值为支付单的url
        String payUrl = alipayClient.pageExecute(request).getBody();

        PayOrder payOrder = new PayOrder();
        payOrder.setOrderId(orderId);
        payOrder.setPayUrl(payUrl);
        payOrder.setStatus(Constants.OrderStatusEnum.PAY_WAIT.getCode());


        //3.订单的状态由CREATE ----> 等待支付
        orderDao.updateOrderPayInfo(payOrder);

        return payOrder;
    }
}
